import styled from "@emotion/styled"
import { useInViewport } from "ahooks"
import React, { memo, useEffect, useRef, useState } from "react"
import Svg from "@/components/base/Svg"
export type SemanticName = "image" | "cover" | "placeholder"
export type ImgObjectFit = "contain" | "cover" | "fill" | "none" | "scale-down" | "inherit"

/**
 * @description LazyImage 组件
 * @param {string} width - 图片的宽度。
 * @param {string} height - 图片的高度。
 * @param {string} objectFit - 图片的 object-fit 属性，用于控制图片的填充方式。
 * @param {Partial<Record<SemanticName, string>>} classNames - 自定义类名，可应用于图片、覆盖层和占位符。
 * @param {Partial<Record<SemanticName, React.CSSProperties>>} styles - 自定义样式，可应用于图片、覆盖层和占位符。
 * @param {string} src - 图片的资源地址（URL）。
 * @param {React.ReactNode} placeholder - 图片加载过程中显示的占位内容。
 * @param {string} alt - 图片的替代文本（alt 属性）。
 * @param {number | number[]} threshold - 视口中触发图片加载的阈值（Intersection Observer 的 threshold）。
 * @param {React.ReactNode} fallback - 图片加载失败时显示的备用内容。
 * @param {(event: Event | string) => void} onError - 图片加载失败时触发的回调函数。
 * @param {(event: Event) => void} onLoad - 图片加载成功时触发的回调函数。
 * @param {React.MouseEventHandler<HTMLDivElement>} onClick - 图片点击时触发的回调函数。
 * @returns {TSX.Element} - 返回 LazyImage 组件实例。
 */

interface LazyImageProps {
    width?: string
    height?: string
    objectFit?: ImgObjectFit
    classNames?: Partial<Record<SemanticName, string>>
    styles?: Partial<Record<SemanticName, React.CSSProperties>>
    src: string
    placeholder?: React.ReactNode
    alt?: string
    threshold?: number | number[]
    fallback?: React.ReactNode
    onError?: (event: Event | string) => void
    onLoad?: (event: Event) => void
    onClick?: React.MouseEventHandler<HTMLDivElement>
}

const Cover = styled.div<{
    width?: string
    height?: string
}>`
    width: ${(props) => props.width || "100%"};
    height: ${(props) => props.height || "100%"};
    position: relative;
    display: inline-block;
    overflow: hidden;
    padding: 0;
    svg {
        width: 24rem;
        height: 24rem;
        fill: #999;
    }
`

const Img = styled.img<{
    objectFit: ImgObjectFit
    width?: string
    height?: string
}>`
    width: ${(props) => props.width || "100%"};
    height: ${(props) => props.height || "100%"};
    display: block;
    object-fit: ${(props) => props.objectFit};
`

const PlaceholderWrapper = styled.div<{
    width?: string
    height?: string
}>`
    width: ${(props) => props.width || "100%"};
    height: ${(props) => props.height || "100%"};
    display: flex;
    justify-content: center;
    align-items: center;
`

const LazyImage: React.FC<LazyImageProps> = ({
    width,
    height,
    src,
    placeholder,
    alt = "",
    classNames = {},
    styles,
    threshold = [],
    fallback = <Svg src={"components/base/icon_fallback.svg"} />,
    objectFit = "cover",
    onError,
    onLoad,
    onClick,
}) => {
    const imageCoverRef = useRef<HTMLDivElement>(null)
    const [isVisible] = useInViewport(imageCoverRef, { threshold })
    const [isLoaded, setIsLoaded] = useState<boolean>(false)
    const [hasError, setHasError] = useState<boolean>(false)

    useEffect(() => {
        if (isVisible && !isLoaded && !hasError) {
            const img = new Image()
            img.onload = (e) => {
                setIsLoaded(true)
                setHasError(false)
                onLoad?.(e)
            }
            img.onerror = (e) => {
                setIsLoaded(false)
                setHasError(true)
                onError?.(e)
            }
            img.src = src

            return () => {
                img.onload = null
                img.onerror = null
            }
        }
    }, [isVisible, isLoaded, hasError, src, placeholder, onLoad, onError])

    useEffect(() => {
        setIsLoaded(false)
        setHasError(false)
    }, [src])

    return (
        <Cover
            ref={imageCoverRef}
            className={classNames?.cover}
            style={styles?.cover}
            onClick={onClick}
            width={width}
            height={height}
        >
            {isLoaded && !hasError ? (
                <Img
                    src={isLoaded ? src : ""}
                    alt={alt}
                    className={classNames.image}
                    style={styles?.image}
                    objectFit={objectFit}
                    width={width}
                    height={height}
                />
            ) : (
                <PlaceholderWrapper
                    width={width}
                    height={height}
                    style={styles?.placeholder}
                >
                    {hasError ? fallback : placeholder}
                </PlaceholderWrapper>
            )}
        </Cover>
    )
}

export default memo(LazyImage)
